home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / bin / tracer.py < prev    next >
Text File  |  2006-06-30  |  13KB  |  422 lines

  1. #!/usr/bin/python
  2. # Copyright (c) 2003 CORE Security Technologies
  3. #
  4. # This software is provided under under a slightly modified version
  5. # of the Apache Software License. See the accompanying LICENSE file
  6. # for more information.
  7. #
  8. # $Id: tracer.py,v 1.4 2003/10/27 17:36:56 jkohen Exp $
  9. #
  10. # Parallel Coordinates traffic grapher.
  11. #
  12. # This grapher uses the pcap library to listen for packets in transit
  13. # over the specified interface. The returned packages can be filtered
  14. # according to a BPF filter (see tcpdump(3) for further information on
  15. # BPF filters). The packets are displayed on a parallel coordinates
  16. # graph that allows the user to visualize the traffic flow on the
  17. # network in real-time.
  18. #
  19. # The graphing part requires Tk support. Note that the user might need
  20. # special permissions to be able to use pcap.
  21. #
  22. # Authors:
  23. #  Gerardo Richarte <gera@coresecurity.com>
  24. #  Javier Kohen <jkohen@coresecurity.com>
  25. #
  26. # Reference for:
  27. #  pcapy: findalldevs, open_live.
  28. #  ImpactPacket.
  29. #  ImpactDecoder.
  30.  
  31. ## Some tunable variables follow.
  32.  
  33. # Period (in ms.) to wait between pcap polls.
  34. POLL_PERIOD = 250
  35.  
  36. # Period (in ms.) to wait between screen refreshes.
  37. REFRESH_PERIOD = 1000
  38.  
  39. # Refresh screen after receiving new packets.
  40. # You might want to turn off fast_draws if it consumes too much CPU,
  41. # for instance, when used under X-Window over a network link.
  42. fast_draws = 1
  43.  
  44. ## End of user configurable section.
  45.  
  46.  
  47. import os
  48. import socket
  49. import sys
  50. import time
  51.  
  52. import Tkinter
  53. from Tkconstants import *
  54.  
  55. import pcapy
  56. from pcapy import open_live, findalldevs, PcapError
  57. import impacket
  58. from impacket import ImpactPacket
  59. from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder
  60.  
  61.  
  62. class NumericAxis:
  63.     def __init__(self,canvas,name,low=0,high=0,direction='vertical'):
  64.         self.canvas = canvas
  65.         self.name = name
  66.         self.setLowerLimit(low)
  67.         self.setHigherLimit(high)
  68.         self.direction = direction
  69.  
  70.     def screenLength(self):
  71.         if self.direction == 'vertical':
  72.             return (self.canvas.winfo_height())-10
  73.         else:
  74.             return (self.canvas.winfo_width())-10
  75.  
  76.     def scaleLength(self):
  77.         delta = self.getHigherLimit()-self.getLowerLimit()
  78.         if not delta:
  79.             delta += 1
  80.         return delta
  81.  
  82.     def unscale(self,coord):
  83.         return int((coord-5)*self.scaleLength()/self.screenLength()+self.getLowerLimit())
  84.  
  85.     def scale(self,value):
  86.         return (value-self.getLowerLimit())*self.screenLength()/self.scaleLength()+5
  87.  
  88.     def setLowerLimit(self,limit):
  89.         if not limit == None:
  90.             self._lowerLimit = limit
  91.  
  92.     def setHigherLimit(self,limit):
  93.         if not limit == None:
  94.             self._higherLimit = limit
  95.  
  96.     def getLowerLimit(self):
  97.         return self._lowerLimit
  98.  
  99.     def getHigherLimit(self):
  100.         return self._higherLimit
  101.  
  102.     def addValue(self,value):
  103.         if self.getLowerLimit() > value:
  104.             self.setLowerLimit(value)
  105.         if self.getHigherLimit() < value:
  106.             self.setHigherLimit(value)
  107.  
  108. class SymbolicAxis(NumericAxis):
  109.     def __init__(self,canvas,name,values=[],direction = 'vertical'):
  110.         NumericAxis.__init__(self,canvas,name,0,len(values)-1,direction)
  111.         self.values = list(values)
  112.  
  113.     def addValue(self,value,sort = 1):
  114.         try:
  115.             self.values.index(value)
  116.             return
  117.         except:
  118.             None
  119.         self.values.append(value)
  120.         if sort:
  121.             self.values.sort()
  122.         self.setHigherLimit(len(self.getValues())-1)
  123.  
  124.     def unscale(self,value):
  125.         try:
  126.             i = NumericAxis.unscale(self, value)
  127.             if i < 0: return None
  128.             return self.getValues()[i]
  129.         except Exception,e:
  130.             return None
  131.  
  132.     def scale(self,value):
  133.         try:
  134.             return NumericAxis.scale(self,self.getValues().index(value))
  135.         except:
  136.             self.addValue(value)
  137.         return NumericAxis.scale(self,self.values.index(value))
  138.  
  139.     def getValues(self):
  140.         return self.values
  141.  
  142. class ParallelCoordinates(Tkinter.Canvas):
  143.     def __init__(self, master=None, cnf={}, **kw):
  144.         apply(Tkinter.Canvas.__init__, (self, master, cnf), kw)
  145.  
  146.         self.lastSelection = None
  147.         self.lastSelectionOval = None
  148.         self._onSelection = None
  149.  
  150.         self.minColor = None
  151.         self.maxColor = None
  152.         self.colorAxis = '_counter'
  153.  
  154.         self.values=[]
  155.         self.mainAxis=SymbolicAxis(self,'mainAxis',[],'horizontal')
  156.  
  157.         master.bind('<Visibility>',self.draw)
  158.         master.bind('<Motion>',self.buttonDown)
  159.         master.bind('<1>',self.buttonDown)
  160.         master.bind('<ButtonRelease-1>',self.buttonUp)
  161.  
  162.     def addAxis(self,axis):
  163.         self.mainAxis.addValue(axis,0)
  164.  
  165.     def sameValue(self,a,b):
  166.         for axis in self.mainAxis.getValues():
  167.             if not a[axis.name] == b[axis.name]:
  168.                 return 0
  169.         return 1
  170.  
  171.     def addValue(self,value):
  172.         for each in self.values:
  173.             if self.sameValue(value,each):
  174.                 each['_counter'] += 1
  175.                 each['timestamp'] = value['timestamp']
  176.                 value = each
  177.                 break
  178.         else:
  179.             value['_counter'] = 1
  180.             for axis in self.mainAxis.getValues():
  181.                 axis.addValue(value[axis.name])
  182.             self.values.append(value)
  183.  
  184.         color = value[self.colorAxis]
  185.         if None == self.minColor or self.minColor > color:
  186.             self.minColor = color
  187.  
  188.         if None == self.maxColor or self.maxColor < color:
  189.             self.maxColor = color
  190.  
  191.     def removeValue(self, value):
  192.         self.values.remove(value)
  193.  
  194.     def basicColor(self,val,fade = 1):
  195.         # color scale is linear going through green -> yellow -> red
  196.         # (lower to higher)
  197.  
  198.         if val < 0.5:
  199.             val += val     # val *= 2 (scale from 0 to 1)
  200.             # between green - yellow
  201.             red   = 64*(1-val)  + 255*val
  202.             green = 200*(1-val) + 255*val
  203.             blue  = 64*(1-val)  + 0
  204.         else:
  205.             val -= 0.5
  206.             val += val
  207.             red   = 255*(1-val) + 255*val
  208.             green = 255*(1-val) + 64*val
  209.             blue  = 0           + 0
  210.  
  211.         return '#%02x%02x%02x' % (int(red*fade), int(green*fade), int(blue*fade))
  212.  
  213.     def fade(self,value):
  214.         return max(0,(120.0-time.time()+value['timestamp'])/120.0)
  215.  
  216.     def color(self,value,fade = 1):
  217.         # color scale is linear going through green -> yellow -> red (lower to higher)
  218.         val = float(value[self.colorAxis]-self.minColor)/(self.maxColor-self.minColor+1)
  219.         return self.basicColor(val,fade)
  220.  
  221.     def drawValueLine(self,value):
  222.         x = -1
  223.         y = -1
  224.         fade = self.fade(value)
  225.         if not fade:
  226.             self.removeValue(value)
  227.             return
  228.  
  229.         color = self.color(value,fade)
  230.  
  231.         for axis in self.mainAxis.getValues():
  232.             px = x
  233.             py = y
  234.             x = self.mainAxis.scale(axis)
  235.             y = axis.scale(value[axis.name])
  236.             if not px == -1:
  237.                 self.create_line(px,py,x,y,fill = color)
  238.  
  239.     def draw(self,event = None):
  240.         # draw axis
  241.         for i in self.find_all():
  242.             self.delete(i)
  243.  
  244.         for axis in self.mainAxis.getValues():
  245.             x = self.mainAxis.scale(axis)
  246.             self.create_line(x,5,x,int(self.winfo_height())-5,fill = 'white')
  247.  
  248.         for value in self.values:
  249.             self.drawValueLine(value)
  250.  
  251. #       draw color range
  252. #        for i in range(200):
  253. #            c = self.basicColor((i+0.0)/200)
  254. #            self.create_line(0,i,100,i,fill = c)
  255.  
  256.     def buttonDown(self,event):
  257.         if (event.state & 0x0100) or (event.type == '4'):
  258.             axis = self.mainAxis.unscale(event.x)
  259.             if not axis: return
  260.             element = axis.unscale(event.y)
  261.             if not element: return
  262.  
  263.             x = self.mainAxis.scale(axis)
  264.             y = axis.scale(element)
  265.  
  266.             if self.lastSelectionOval:
  267.                 self.delete(self.lastSelectionOval)
  268.             self.lastSelectionOval = self.create_oval(x-3,y-3,x+3,y+3,fill = "yellow")
  269.  
  270.             if not self.lastSelection == (axis,element):
  271.                 self.lastSelection = (axis,element)
  272.                 if self._onSelection:
  273.                     self._onSelection(self.lastSelection)
  274.  
  275.  
  276.     def buttonUp(self,event):
  277.         if self.lastSelectionOval:
  278.             self.delete(self.lastSelectionOval)
  279.             self.lastSelectionOval = None
  280.             self.lastSelection = None
  281.             if self._onSelection:
  282.                 self._onSelection(None)
  283.  
  284.     def onSelection(self,_onSelection):
  285.         self._onSelection = _onSelection
  286.  
  287.  
  288. class Tracer:
  289.     def __init__(self, interface = 'eth0', filter = ''):
  290.         print "Tracing interface %s with filter `%s'." % (interface, filter)
  291.  
  292.         self.tk = Tkinter.Tk()
  293.         self.pc = ParallelCoordinates(self.tk,background = "black")
  294.         self.pc.pack(expand=1, fill="both")
  295.         self.status = Tkinter.Label(self.tk)
  296.         self.status.pack()
  297.         self.tk.tkraise()
  298.         self.tk.title('Personal SIDRA (IP-Tracer)')
  299.  
  300.         self.pc.addAxis(NumericAxis(self.pc, 'proto',256))
  301.         self.pc.addAxis(SymbolicAxis(self.pc,'shost'))
  302.         self.pc.addAxis(SymbolicAxis(self.pc,'sport'))
  303.         self.pc.addAxis(SymbolicAxis(self.pc,'dport'))
  304.         self.pc.addAxis(SymbolicAxis(self.pc,'dhost'))
  305.         self.pc.onSelection(self.newSelection)
  306.  
  307.         self.interface = interface
  308.         self.filter = filter
  309.  
  310.     def timerDraw(self,event = None):
  311.         self.pc.draw()
  312.         self.tk.after(REFRESH_PERIOD, self.timerDraw);
  313.  
  314.     def start(self):
  315.         self.p = open_live(self.interface, 1600, 0, 100)
  316. ##         self.p.setnonblock(1)
  317.         if self.filter:
  318.             self.p.setfilter(self.filter)
  319.  
  320.         # Query the type of the link and instantiate a decoder accordingly.
  321.         datalink = self.p.datalink()
  322.         if pcapy.DLT_EN10MB == datalink:
  323.             self.decoder = EthDecoder()
  324.         elif pcapy.DLT_LINUX_SLL == datalink:
  325.             self.decoder = LinuxSLLDecoder()
  326.         else:
  327.             raise Exception("Datalink type not supported: " % datalink)
  328.  
  329.         self.tk.after(POLL_PERIOD, self.poll)
  330.         self.tk.after(REFRESH_PERIOD, self.timerDraw);
  331.         self.tk.bind('q',self.quit)
  332.         self.tk.mainloop()
  333.  
  334.     def quit(self,event):
  335.         self.tk.quit()
  336.  
  337.     def poll(self,event = None):
  338.         self.tk.after(POLL_PERIOD, self.poll)
  339.         received = 0
  340.         while 1:
  341.             try:
  342.                 hdr, data = self.p.next()
  343.             except PcapError, e:
  344.                 break
  345.             self.newPacket(hdr.getcaplen(), data, hdr.getts()[0])
  346.             received = 1
  347.         if received and fast_draws:
  348.             self.pc.draw()
  349.  
  350.     def newPacket(self, len, data, timestamp):
  351.         try:
  352.             p = self.decoder.decode(data)
  353.         except Exception, e:
  354.             pass
  355.         value = {}
  356.         try:
  357.         value['timestamp']=timestamp
  358.             value['shost']=p.child().get_ip_src()
  359.             value['dhost']=p.child().get_ip_dst()
  360.             value['proto']=p.child().child().protocol
  361.             value['sport']=-1
  362.             value['dport']=-1
  363.         except:
  364.             return
  365.  
  366.         try:
  367.             if value['proto'] == socket.IPPROTO_TCP:
  368.                 value['dport']=p.child().child().get_th_dport()
  369.                 value['sport']=p.child().child().get_th_sport()
  370.             elif value['proto'] == socket.IPPROTO_UDP:
  371.                 value['dport']=p.child().child().get_uh_dport()
  372.                 value['sport']=p.child().child().get_uh_sport()
  373.         except:
  374.             pass
  375.  
  376.         self.pc.addValue(value)
  377.  
  378.     def setStatus(self,status):
  379.         self.status.configure(text = status)
  380.  
  381.     def newSelection(self, selection):
  382.         if selection:
  383.             self.setStatus('%s:%s' % (selection[0].name, selection[1]))
  384.         else:
  385.             self.setStatus('')
  386.  
  387. def getInterfaces():
  388.     # Grab a list of interfaces that pcap is able to listen on.
  389.     # The current user will be able to listen from all returned interfaces,
  390.     # using open_live to open them.
  391.     ifs = findalldevs()
  392.  
  393.     # No interfaces available, abort.
  394.     if 0 == len(ifs):
  395.         return "You don't have enough permissions to open any interface on this system."
  396.  
  397.     return ifs
  398.  
  399. def printUsage():
  400.         print """Usage: %s [interface [filter]]
  401. Interface is the name of a local network interface, see the list of available interfaces below.
  402. Filter is a BPF filter, as described in tcpdump(3)'s man page.
  403.  
  404. Available interfaces for this user: %s
  405. """ % (sys.argv[0], getInterfaces())
  406.  
  407. def main():
  408.     if len(sys.argv) == 1:
  409.         printUsage()
  410.         graph = Tracer()
  411.     elif len(sys.argv) == 2:
  412.         graph = Tracer(sys.argv[1])
  413.     elif len(sys.argv) == 3:
  414.         graph = Tracer(sys.argv[1],sys.argv[2])
  415.     else:
  416.         printUsage()
  417.         sys.exit(1)
  418.     graph.start()
  419.  
  420. main()
  421.  
  422.